package chooongg.base.utils

import java.io.*
import java.nio.ByteBuffer
import java.nio.channels.FileChannel
import java.nio.charset.Charset
import java.util.*

/**
 * 写文件4输入流
 *
 * @param is     输入流
 * @param append 是否附加写入
 */
@JvmOverloads
fun File.writeFileFromIS(`is`: InputStream?, append: Boolean = false): Boolean {
    if (!createOrExistsFile() || `is` == null) return false
    var os: OutputStream? = null
    try {
        os = BufferedOutputStream(FileOutputStream(this, append))
        val data = ByteArray(DEFAULT_BUFFER_SIZE)
        var len: Int
        while (`is`.read(data, 0, DEFAULT_BUFFER_SIZE).apply { len = this } != -1) {
            os.write(data, 0, len)
        }
        return true
    } catch (e: IOException) {
        e.printStackTrace()
        return false
    } finally {
        try {
            `is`.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
        try {
            os?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }

    }
}

/**
 * 写文件4字节数组
 *
 * @param bytes  字节数组
 * @param append 是否附加写入
 */
@JvmOverloads
fun File.writeFileFromBytesByStream(bytes: ByteArray?, append: Boolean = false): Boolean {
    if (bytes == null || !createOrExistsFile()) return false
    var bos: BufferedOutputStream? = null
    return try {
        bos = BufferedOutputStream(FileOutputStream(this, append))
        bos.write(bytes)
        true
    } catch (e: IOException) {
        e.printStackTrace()
        false
    } finally {
        try {
            bos?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
}


/**
 * 写文件4字节数组
 *
 * @param bytes   字节数组
 * @param append  是否附加写入
 * @param isForce 是否强制写入
 */
@JvmOverloads
fun File.writeFileFromBytesByChannel(
    bytes: ByteArray?,
    append: Boolean = false,
    isForce: Boolean
): Boolean {
    if (bytes == null) return false
    var fc: FileChannel? = null
    try {
        fc = FileOutputStream(this, append).channel
        fc!!.position(fc.size())
        fc.write(ByteBuffer.wrap(bytes))
        if (isForce) fc.force(true)
        return true
    } catch (e: IOException) {
        e.printStackTrace()
        return false
    } finally {
        try {
            fc?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }

    }
}

/**
 * 写文件4字节数组
 *
 * @param bytes   字节数组
 * @param append  是否附加写入
 * @param isForce 是否强制写入
 */
@JvmOverloads
fun File.writeFileFromBytesByMap(
    bytes: ByteArray?,
    append: Boolean = false,
    isForce: Boolean
): Boolean {
    if (bytes == null || !createOrExistsFile()) return false
    var fc: FileChannel? = null
    try {
        fc = FileOutputStream(this, append).channel
        val mbb = fc!!.map(FileChannel.MapMode.READ_WRITE, fc.size(), bytes.size.toLong())
        mbb.put(bytes)
        if (isForce) mbb.force()
        return true
    } catch (e: IOException) {
        e.printStackTrace()
        return false
    } finally {
        try {
            fc?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }

    }
}

/**
 * 写文件4字符串
 *
 * @param content 字符串内容
 * @param append  是否附加写入
 */
@JvmOverloads
fun File.writeFileFromString(content: String?, append: Boolean = false): Boolean {
    if (content == null) return false
    if (!createOrExistsFile()) return false
    var bw: BufferedWriter? = null
    return try {
        bw = BufferedWriter(FileWriter(this, append))
        bw.write(content)
        true
    } catch (e: IOException) {
        e.printStackTrace()
        false
    } finally {
        try {
            bw?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }

    }
}

///////////////////////////////////////////////////////////////////////////
// 读写分界线
///////////////////////////////////////////////////////////////////////////

/**
 * 读文件2字符串集合
 *
 * @param st          起始行(默认开头)
 * @param end         截至行(默认结尾)
 * @param charsetName 字符集名称
 */
@JvmOverloads
fun File.readFile2List(
    st: Int = 0,
    end: Int = 0x7FFFFFFF,
    charsetName: String? = null
): List<String>? {
    if (notExists()) return null
    if (st > end) return null
    var reader: BufferedReader? = null
    try {
        var line: String
        var curLine = 1
        val list = ArrayList<String>()
        reader = if (charsetName.isSpace()) {
            BufferedReader(InputStreamReader(FileInputStream(this)))
        } else {
            BufferedReader(
                InputStreamReader(FileInputStream(this), charsetName!!)
            )
        }
        while (reader.readLine().apply { line = this } != null) {
            if (curLine > end) break
            if (curLine in st..end) list.add(line)
            ++curLine
        }
        return list
    } catch (e: IOException) {
        e.printStackTrace()
        return null
    } finally {
        try {
            reader?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
}

/**
 * 读文件2字符串
 *
 * @param charsetName 字符集名称
 */
@JvmOverloads
fun File.readFile2String(charsetName: String? = null): String? {
    val bytes = readFile2BytesByStream() ?: return null
    return if (charsetName.isSpace()) {
        String(bytes)
    } else {
        try {
            String(bytes, Charset.forName(charsetName))
        } catch (e: UnsupportedEncodingException) {
            e.printStackTrace()
            ""
        }

    }
}

/**
 * 读文件2字节数组
 */
fun File.readFile2BytesByStream(): ByteArray? {
    if (notExists()) return null
    return try {
        is2Bytes(FileInputStream(this))
    } catch (e: FileNotFoundException) {
        e.printStackTrace()
        null
    }

}

/**
 * 读文件2字节数组
 */
fun File.readFile2BytesByChannel(): ByteArray? {
    if (notExists()) return null
    var fc: FileChannel? = null
    try {
        fc = RandomAccessFile(this, "r").channel
        val byteBuffer = ByteBuffer.allocate(fc!!.size().toInt())
        while (true) {
            if (fc.read(byteBuffer) <= 0) break
        }
        return byteBuffer.array()
    } catch (e: IOException) {
        e.printStackTrace()
        return null
    } finally {
        try {
            fc?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }

    }
}

/**
 * 读文件2字节数组
 */
fun File.readFile2BytesByMap(): ByteArray? {
    if (notExists()) return null
    var fc: FileChannel? = null
    try {
        fc = RandomAccessFile(this, "r").channel
        val size = fc!!.size().toInt()
        val mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, size.toLong()).load()
        val result = ByteArray(size)
        mbb.get(result, 0, size)
        return result
    } catch (e: IOException) {
        e.printStackTrace()
        return null
    } finally {
        try {
            fc?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }

    }
}

private fun is2Bytes(`is`: InputStream?): ByteArray? {
    if (`is` == null) return null
    var os: ByteArrayOutputStream? = null
    try {
        os = ByteArrayOutputStream()
        val b = ByteArray(DEFAULT_BUFFER_SIZE)
        var len: Int
        while (`is`.read(b, 0, DEFAULT_BUFFER_SIZE).apply { len = this } != -1) {
            os.write(b, 0, len)
        }
        return os.toByteArray()
    } catch (e: IOException) {
        e.printStackTrace()
        return null
    } finally {
        try {
            `is`.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }

        try {
            os?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }

    }
}